package com.chindeo.h5.x5;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;


import com.chindeo.h5.x5.view.X5WebView;
import com.lazylibs.lifecycle.NetworkStateManager;
import com.lazylibs.lifecycle.net.NetStateChangeObserver;
import com.lazylibs.lifecycle.net.NetworkType;
import com.lazylibs.util.NetworkUtils;
import com.lazylibs.util.RegexUtils;
import com.lazylibs.weight.skeleton.IViewSkeleton;
import com.lazylibs.weight.skeleton.SimpleStateView;
import com.lazylibs.weight.skeleton.Skeleton;
import com.lazylibs.weight.skeleton.ViewSkeleton;
import com.lazylibs.weight.skeleton.ViewState;
import com.tencent.smtt.export.external.interfaces.WebResourceError;
import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewClient;

import java.util.LinkedHashMap;
import java.util.Map;

public class X5Helper {

    public final static String H5_LOADDING_STATE_CHANGE_ACTION = "com.h5.loadding.state";
    public final static String EXTRA_H5_LOADDING_STATE = "com.h5.loadding.state.extra";

    private X5WebView webView;
    private ViewSkeleton skeleton;
    private OnInvalidUrlHandler handler;
    private Map<String, Object> jsInterface = new LinkedHashMap<>();
    private NetStateChangeObserver observer;

    public static void destroy(X5Helper helper) {
        if (helper != null) {
            helper.destroy();
            helper = null;
        }
    }

    public X5WebView getWebView() {
        return webView;
    }

    public X5Helper setUserAgent(String userAgent) {
        String current = webView.getSettings().getUserAgentString();
        if (!TextUtils.isEmpty(userAgent) && !current.contains(userAgent)) {
            webView.getSettings().setUserAgentString(current + userAgent);
        }
        return this;
    }

    public X5Helper setHandler(OnInvalidUrlHandler handler) {
        this.handler = handler;
        return this;
    }

    public X5Helper setSkeleton(ViewSkeleton skeleton) {
        this.skeleton = skeleton;
        return this;
    }

    private X5Helper(FrameLayout parent, Object... args) {
        webView = new X5WebView(parent.getContext());
        parent.addView(webView, new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        initLocalBroadcastReceiver();
    }


    private X5Helper setJsInterfaces(Map<String, Object> jsInterface) {
        if (jsInterface != null && !jsInterface.isEmpty()) {
            this.jsInterface.clear();
            for (Map.Entry<String, Object> entry : jsInterface.entrySet()) {
                webView.addJavascriptInterface(entry.getValue(), entry.getKey());
            }
            this.jsInterface.putAll(jsInterface);
        }
        return this;
    }

    private void destroy() {
        if (observer != null) {
            NetworkStateManager.unregisterObserver(observer);
            observer = null;
        }
        if (jsInterface != null && !jsInterface.isEmpty()) {
            for (Map.Entry<String, Object> entry : jsInterface.entrySet()) {
                webView.removeJavascriptInterface(entry.getKey());
            }
            jsInterface.clear();
            jsInterface = null;
        }
        if (webView != null) {
            webView.destroy();
            webView = null;
        }
    }

    private void initLocalBroadcastReceiver() {
        // 监听本地广播
        if (observer == null) {
            NetworkStateManager.registerObserver(observer = new NetStateChangeObserver() {
                @Override
                public void onNetDisconnected() {

                }

                @Override
                public void onNetConnected(NetworkType networkType) {
                    if (webView != null) {
                        if (TextUtils.isEmpty(webView.getUrl()) || webView.getUrl().contains("blank") && handler != null) {
                            handler.invalidUrl(webView);
                        } else {
                            if (skeleton.isShow()) {
                                webView.reload();
                            }
                        }
                    }
                }
            });
        }
    }

    public interface OnInvalidUrlHandler {
        void invalidUrl(X5WebView webView);
    }

    public static class X5WebChromeClient extends IWebChromeClient {
        private ViewSkeleton skeleton;

        private boolean isEmpty() {
            return skeleton == null;
        }

        public X5WebChromeClient() {
        }

        public X5WebChromeClient(@NonNull ViewSkeleton skeleton) {
            this.skeleton = skeleton;
        }

        @Override
        public void onReceivedTitle(WebView view, String title) {
            if (!TextUtils.isEmpty(title)) {
                if (title.toLowerCase().contains("error") ||
                        title.contains("找不到网页")) {
                    if (skeleton != null) {
                        skeleton.show(ViewState.ERROR);
                    }
                    sendState(view.getContext(), ViewState.ERROR);
                }
            }
        }


        public static class X5WebViewClient extends WebViewClient {
            protected boolean isError;
            protected boolean isPageFinished = false;
            protected ViewSkeleton skeleton;

            protected boolean isEmpty() {
                return skeleton == null;
            }

            public X5WebViewClient() {
                this(null);
            }

            public X5WebViewClient(ViewSkeleton skeleton) {
                this.skeleton = skeleton;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                isPageFinished = false;
                isError = false;
                if (skeleton != null) {
                    skeleton.show(ViewState.LOADING);
                }
                sendState(view.getContext(), ViewState.LOADING);
            }

            protected void onReallyFinished(WebView view, String url) {
                if (skeleton != null) {
                    skeleton.hide();
                }
                sendState(view.getContext(), -1);
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                if (isPageFinished) { // onReceivedError 处理了异常
                    isPageFinished = false; // 初始化
                    return;
                }
                isPageFinished = true;
                view.requestFocus();
                if (!RegexUtils.isURL(url)) {
                    if (skeleton != null) {
                        skeleton.show(ViewState.ERROR);
                    }
                    sendState(view.getContext(), ViewState.ERROR);
                } else if (!isError) {
                    onReallyFinished(view, url);
                } else {
                    if (skeleton != null) {
                        skeleton.show(ViewState.ERROR);
                    }
                    sendState(view.getContext(), ViewState.ERROR);
                }

            }

            // 旧版本，会在新版本中也可能被调用，所以加上一个判断，防止重复显示
            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                super.onReceivedError(view, errorCode, description, failingUrl);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    return;
                }
                // 在这里显示自定义错误页
                isError = true;
                if (!isPageFinished) {
                    if (skeleton != null) {
                        if (!NetworkUtils.isConnected(view.getContext())) {
                            skeleton.show(ViewState.ERROR);
                        } else if (ERROR_HOST_LOOKUP == errorCode) {
                            skeleton.show(ViewState.EMPTY);
                        }
                    }
                    sendState(view.getContext(), ViewState.ERROR);
                    isPageFinished = true;
                }
            }

            // 新版本，只会在Android6及以上调用
            @Override
            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
                super.onReceivedError(view, request, error);
                if (request.isForMainFrame()) {// 在这里加上个判断 // 或者： if(request.getUrl().toString() .equals(getUrl()))
                    // 显示错误界面
                    isError = true;
                    int statusCode = error.getErrorCode();
                    if (!isPageFinished) {
                        if (skeleton != null) {
                            if (!NetworkUtils.isConnected(view.getContext())) {
                                skeleton.show(ViewState.ERROR);
                            } else if (ERROR_HOST_LOOKUP == statusCode) {
                                skeleton.show(ViewState.EMPTY);
                            }
                        }
                        sendState(view.getContext(), ViewState.ERROR);
                        isPageFinished = true;
                    }
                }
            }
        }

        private static void sendState(Context context, int viewState) {
            LocalBroadcastManager.getInstance(context)
                    .sendBroadcast(new Intent(H5_LOADDING_STATE_CHANGE_ACTION)
                            .addCategory(X5WebView.getActivity(context).getClass().getSimpleName())
                            .putExtra(EXTRA_H5_LOADDING_STATE, viewState));
        }

    }
        public static class Builder {
            private String userAgent;

            private boolean isGame = false;
            private ViewSkeleton skeleton;
            private X5WebChromeClient.X5WebViewClient webViewClient;
            private X5WebChromeClient webChromeClient;
            private OnInvalidUrlHandler handler;
            private Skeleton.IStateView stateView;
            private Map<String, Object> jsInterface;

            public Builder() {
            }

            public Builder action1(IViewSkeleton skeleton) {
                this.skeleton = (ViewSkeleton) skeleton;
                return this;
            }

            public Builder action1(Skeleton.IStateView stateView) {
                this.stateView = stateView;
                return this;
            }

            public Builder action2(X5WebChromeClient.X5WebViewClient webViewClient, X5WebChromeClient webChromeClient) {
                this.webViewClient = webViewClient;
                this.webChromeClient = webChromeClient;
                return this;
            }

            public Builder setGame(boolean game) {
                isGame = game;
                return this;
            }

            public Builder setUserAgent(String userAgent) {
                this.userAgent = userAgent;
                return this;
            }

            public Builder setHandler(OnInvalidUrlHandler handler) {
                this.handler = handler;
                return this;
            }

            public Builder setJsInterface(Map<String, Object> jsInterface) {
                this.jsInterface = jsInterface;
                return this;
            }

            private ViewSkeleton getSkeleton(X5WebView webView) {
                if (skeleton == null) {
                    skeleton = Skeleton.create(webView, new SimpleStateView() {
                        @Override
                        public View onCreateView(Context context, ViewGroup viewGroup, int i) {
                            View view = null;
                            switch (i) {
                                case ViewState.NO_INTERNET:
                                case ViewState.ERROR:
                                case ViewState.LOADING:
                                case ViewState.EMPTY:
                                    view = stateView == null ? super.onCreateView(context, viewGroup, i) : stateView.onCreateView(context, viewGroup, i);
                                    break;
                            }
                            return view;
                        }
                    });
                    skeleton.setOnClickListener(new ViewSkeleton.OnClickListener() {
                        @Override
                        public void onClick(View view, int viewState) {
                            switch (viewState) {
                                case ViewState.NO_INTERNET:
                                case ViewState.ERROR:
                                    skeleton.show(ViewState.LOADING);
                                    if (TextUtils.isEmpty(webView.getUrl()) || webView.getUrl().contains("blank") && handler != null) {
                                        handler.invalidUrl(webView);
                                    } else {
                                        webView.reload();
                                    }
                                    break;
                                case ViewState.EMPTY:
                                    break;
                                case ViewState.LOADING:
                                    break;
                            }
                        }
                    });
                }
                return skeleton;
            }

            private X5Helper initHelper(X5Helper helper) {
                if (webChromeClient != null && webViewClient != null) {
                    if (webViewClient.isEmpty()) {
                        if (webChromeClient.isEmpty()) {
                            webViewClient.skeleton = getSkeleton(helper.getWebView());
                            webChromeClient.skeleton = getSkeleton(helper.getWebView());
                        } else {
                            webViewClient.skeleton = webChromeClient.skeleton;
                        }
                    } else {
                        if (webChromeClient.isEmpty()) {
                            webChromeClient.skeleton = webViewClient.skeleton;
                        }
                    }
                    helper.webView.setWebChromeClient(webChromeClient);
                    helper.webView.setWebViewClient(webViewClient);
                } else {
                    helper.webView.setWebChromeClient(webChromeClient == null ? new X5WebChromeClient(getSkeleton(helper.getWebView())) : webChromeClient);
                    helper.webView.setWebViewClient(webViewClient == null ? new X5WebChromeClient.X5WebViewClient(getSkeleton(helper.getWebView())) : webViewClient);
                }
                return helper.setUserAgent(userAgent).setHandler(handler).setSkeleton(getSkeleton(helper.getWebView())).setJsInterfaces(jsInterface);

            }

            public X5Helper build(@NonNull FrameLayout parent) {
                return initHelper(isGame ? new X5Helper(parent, "") : new X5Helper(parent));
            }

            public X5Helper build(@NonNull X5WebView webView) {
                return initHelper(isGame ? new X5Helper(webView, "") : new X5Helper(webView));
            }
        }
}